﻿using Soft.Data;
using Soft.Net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Soft.Service
{
    /// <summary>
    /// job服务控制器   管理/控制jobServices中的服务
    /// </summary>
    public  sealed class JobServiceController:BaseService,IDebug
    {

        /// <summary>
        /// job服务控制器
        /// </summary>
        public JobServiceController() : base("Jobs service controller", "JobService")
        {
            //错误处理程序
            this.mProcessCollection.Error += this.OnError;
            //处理信息程序
            this.mProcessCollection.Information += this.OnInformation;
            //执行方法的指令
            this.mProcessCollection.ExecuteMethodCallInstruction = new ExecuteMethodCallInstructionEventHandle(this.LocalMethodCall);
            //初始化拦截器
            this.InitCommandInterpreter();

            //注册TcpChannel
            Result result = NetManager.RegisterTcpChannel(NetManager.JobServerChannelName, new ushort?(NetManager.JobServicePort));
            if (!result.Succeed)
            {
                this.OnError(result.Error);
            }

            //注册服务类型
            result = NetManager.RegisterServiceType<ServiceRemoteMethodCallPerformer>();
            if (!result.Succeed)
            {
                base.State = ServerState.Error;
                result.AddError(result);
                this.OnError(result.Error);
            }
        }

  
        /// <summary>
        /// 是否开启debug模式
        /// </summary>
        public bool Debug { get; private set; }


        /// <summary>
        /// 错误处理程序
        /// </summary>
        /// <param name="error"></param>
        internal new void OnError(Information error)
        {
            base.OnError(error);
        }


        internal CarrierJson OnReceivedMethodCallInstruction(CallMethodInstruction callMethodInstruction)
        {
            return this.Invoke(callMethodInstruction);
        }


        /// <summary>
        /// 服务启动时的操作
        /// </summary>
        /// <returns></returns>

        protected override Result OnStart()
        {
            Result result = new Result();
            //加载配置文件的服务实例
            this.LoadConfigFile();

            //给jobInstance实例 绑定错误处理程序
            this.mProcessCollection.JobInstanceList.ForEach(delegate (JobInstance inst)
            {
                try
                {
                    inst.Instance = (BaseJob)Activator.CreateInstance(inst.InstanceType);
                    inst.Instance.ExecuteMethodCallInstruction = inst.ExecuteMethodHandle;
                    if (inst.InstanceType.TypeAs(typeof(IServerControl)))
                    {
                        inst.Instance.Error += delegate (Information e)
                        {
                            this.OnError("业务服务：" + ((IServerControl)inst.Instance).ServiceName + " 出现错误，错误是：" + e.Text);
                        };
                    }
                    else if (inst.InstanceType.TypeAs(typeof(ITimedTaskControl)))
                    {
                        inst.Instance.Error += delegate (Information e)
                        {
                            this.OnError("定时业务：" + ((ITimedTaskControl)inst.Instance).TaskName + " 出现错误，错误是：" + e.Text);
                        };
                    }
                    else
                    {
                        inst.Instance.Error += delegate (Information e)
                        {
                            this.OnError("业务对象：" + inst.InstanceType.FullName + " 出现错误，错误是：" + e.Text);
                        };
                    }
                }
                catch (Exception e)
                {
                    this.OnError(e);
                }
            });


            //启动serviceController中 被标记的自动启动的服务
            this.mProcessCollection.Services.FindAll((JobInstance s) => s.StartType == JobServiceStartType.Automatic).ForEach(delegate (JobInstance s)
            {
                try
                {
                    IServerControl serverControl = (IServerControl)s.Instance;
                    Result result2 = serverControl.Start();
                    if (!result2.Succeed)
                    {
                        result.AddError(result2);
                    }
                }
                catch (Exception exception)
                {
                    result.AddError(exception, this);
                }
            });

            //启动任务调度程序，开启定时器，定时扫描要执行的任务
            Result result3 = this.mProcessCollection.TimedTasks.Start();
            if (!result3.Succeed)
            {
                result.AddError(result3);
            }


            //远程方法执行器
            ServiceRemoteMethodCallPerformer.JobService = this;

            //开启控制器命令拦截器
            this.mRemoteControlCommandInterpreter.Start();
            return result;
        }


       /// <summary>
       /// 服务关闭时要执行的操作
       /// </summary>
        protected override void OnStop()
        {
            ServiceRemoteMethodCallPerformer.JobService = null;
            if (base.State == ServerState.Started || base.State == ServerState.Error)
            {
                base.State = ServerState.Stopping;
                this.mRemoteControlCommandInterpreter.Stop();
                this.mBroadcast.Stop();
                this.mProcessCollection.Services.ForEach(delegate (JobInstance s)
                {
                    try
                    {
                        //停止服务
                        ((IServerControl)s.Instance).Stop();
                        //移除服务中Error委托
                        ObjectExtensions.RemoveAllEventDelegate((IServerControl)s.Instance, "Error");
                    }
                    catch (Exception e)
                    {
                        this.OnError(e);
                    }
                });
                this.mProcessCollection.JobInstanceList.ForEach(delegate (JobInstance inst)
                {
                    try
                    {
                        if (inst.Instance != null)
                        {
                            inst.Instance.Dispose();
                            inst.Instance = null;
                        }
                    }
                    catch (Exception e)
                    {
                        this.OnError(e);
                    }
                });
                base.State = ServerState.Stopped;
            }
        }


        /// <summary>
        /// 释放服务(注销所有的通道)
        /// </summary>
        protected override void OnDispose()
        {
            this.OnStop();
            NetManager.UnregisterAllChannels();
        }


        /// <summary>
        /// 初始化命令拦截器
        /// </summary>
        private void InitCommandInterpreter()
        {
            ///心跳map
            this.mRemoteControlCommandInterpreter.Add(RemoteControlCode.Heartbeat.Code, typeof(HeartbeatRemoteControlProcessor), "执行心跳信号", new object[0]);
            //获取当前业务功能列表map
            this.mRemoteControlCommandInterpreter.Add(RemoteControlCode.GetRemoteJobs.Code, typeof(GetJobsRemoteControlProcessor), "获得当前业务服务器的业务功能列表", new object[]
            {
                this.mProcessCollection
            });
            //获取系统负载map
            this.mRemoteControlCommandInterpreter.Add(RemoteControlCode.GetSystemLoad.Code, typeof(GetSystemLoadControlProcessor), "获取系统负载状态", new object[0]);
            //心跳消失
            this.mRemoteControlCommandInterpreter.HeartbeatDisappear += delegate ()
            {
                //开启广播
                this.mBroadcast.Start();
            };
            //心跳恢复
            this.mRemoteControlCommandInterpreter.HeartbeatRecover += delegate ()
            {
                //广播开启等待
                this.mBroadcast.Hold();
            };
        }


        /// <summary>
        /// 写入Infomation信息
        /// </summary>
        /// <param name="info"></param>
        private void OnInformation(Information info)
        {
            base.WriteLog(info.Text, true);
        }


        /// <summary>
        /// 加载配置文件
        /// </summary>
        private void LoadConfigFile()
        {
            this._AssemblyList.Clear();
            LocalJobServiceConfig localJobServiceConfig = new LocalJobServiceConfig();
            //清空方法单元集合
            this.mProcessCollection.ProcessItems.Clear();
            //加载LocalJobServiceConfig文件
            localJobServiceConfig.Load();
            //是否是Debug模式
            this.Debug = localJobServiceConfig.Debug;
            this.mProcessCollection.Debug = this.Debug;
            //广播的实例名称
            this.mBroadcast.InstanceName = localJobServiceConfig.InstanceName;
            //广播的IP地址
            this.mBroadcast.ListeningIP = localJobServiceConfig.ListeningIP;
            //服务配置DllConfig&ConnectStrings连接字符串
            ServiceConfig service = localJobServiceConfig.Service;

            //添加数据库连接字符串集合
            foreach (DBConnectionConfigGroup dbconnectionConfigGroup in localJobServiceConfig.DBConnections)
            {
                LocalJobServiceSet.DBConnectionGroups.Add(new DBConnectionGroup(dbconnectionConfigGroup.DBType, dbconnectionConfigGroup.MethodFlags, dbconnectionConfigGroup.PrimaryDBConnectionString, dbconnectionConfigGroup.StandbyDBConnectionString));
            }

            ///获取程序集列表
            List<string> list = new List<string>();
            using (IEnumerator<DllConfig> enumerator2 = service.GetEnumerator())
            {
                while (enumerator2.MoveNext())
                {
                    DllConfig dll = enumerator2.Current;
                    if (list.Exists((string e) => e == dll.File))
                    {
                        this.OnError("This dll file '" + Path.GetFullPath(dll.File) + "' is already loaded.");
                    }
                    else
                    {
                        list.Add(dll.File);
                        Assembly assembly = this.mProcessCollection.AppendDll(dll);
                        if (assembly != null)
                        {
                            this._AssemblyList.Add(assembly);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// 调用方法
        /// </summary>
        /// <param name="callMethodInstruction"></param>
        /// <returns></returns>
        private CarrierJson Invoke(CallMethodInstruction callMethodInstruction)
        {
            CarrierJson carrierJson = new CarrierJson();
            //如果是控制指令
            if (ControlCode.IsControlCode(callMethodInstruction.FunctionCode))
            {
                Stopwatch stopwatch = null;
                if (this.Debug)
                {
                    stopwatch = new Stopwatch();
                    stopwatch.Start();
                }
                try
                {
                    //控制器命令拦截器执行方法指令
                    carrierJson.GetData(this.mRemoteControlCommandInterpreter.Execute(callMethodInstruction));
                    if (Debug)
                    {
                        Console.WriteLine($"控制信号:{callMethodInstruction.FunctionCode}");
                    }
                }
                catch (Exception innerException)
                {
                    InternalSystemException ex = new InternalSystemException("An error occurred while executing the control command.", this, innerException);
                    this.OnError(ex);
                    carrierJson.AddError(ex, null);
                }
                if (this.Debug)
                {
                    stopwatch.Stop();
                    carrierJson.CallMilliseconds = stopwatch.ElapsedMilliseconds;
                }
            }  //如果是功能指令
            else if (FunctionCode.IsFunctonCode(callMethodInstruction.FunctionCode, false))
            {
                FunctionSign functionSign = new FunctionSign(callMethodInstruction.FunctionCode);

                //从功能项中获取相匹配的功能码的功能项，并执行功能
                if (this.mProcessCollection.ProcessItems.Exists((ProcessItem e) => e.FunctionSign.FullCode == functionSign.FullCode))
                {
                    ProcessItem processItem = this.mProcessCollection.ProcessItems.Find((ProcessItem e) => e.FunctionSign.FullCode == functionSign.FullCode);
                    if (processItem != null)
                    {
                        //如果是TimedTaskControl正在运行  则返回错误
                        if (processItem.JobClassType.TypeAs(typeof(ITimedTaskControl)) && processItem.Method.MethodName == "Run" && ((ITimedTaskControl)processItem.Instance.Instance).Running)
                        {
                            carrierJson.AddError(SystemErrors.TimedTaskHasRunning);
                            return carrierJson;
                        }
                        if (this.Debug)
                        {
                            LocalJobServiceSet.WriteRemotingCallLog(callMethodInstruction, processItem.Method);
                        }
                        try
                        {
                            //调用功能项的Invoke方法
                            InvokeResult invokeResult = processItem.Invoke(callMethodInstruction.JsonParams, this.Debug);
                            carrierJson.GetData(invokeResult);
                            return carrierJson;
                        }
                        catch (Exception innerException2)
                        {
                            InternalSystemException ex2 = new InternalSystemException("在提交业务请求时发生错误，请与开发者联系。(" + callMethodInstruction.FunctionCode + ")", this, innerException2);
                            this.OnError(ex2);
                            carrierJson.AddError(ex2, null);
                            return carrierJson;
                        }
                    }
                    InternalSystemException ex3 = new InternalSystemException("没有找到" + callMethodInstruction.FunctionCode + "对应的处理业务的进程单元实例。", this, null);
                    this.OnError(ex3);
                    carrierJson.AddError(ex3, null);
                }
                else
                {
                    carrierJson.AddError(string.Concat(new string[]
                    {
                        "这个服务器中不存在这个功能号“",
                        callMethodInstruction.FunctionCode,
                        "”的定义。'",
                         NetManager.LocalHostIpsDescribe,
                        "'."
                    }), null);
                }
            }
            else
            {
                carrierJson.AddError("功能号“" + callMethodInstruction.FunctionCode + "”格式错误。", null);
            }
            return carrierJson;
        }


        /// <summary>
        /// rpc远程执行时需要执行的方法
        /// </summary>
        /// <param name="callMethodInstruction"></param>
        /// <returns></returns>
        private CarrierJson LocalMethodCall(CallMethodInstruction callMethodInstruction)
        {
            //如果要调用的功能号所表示的功能存在，则调用相对应的功能
            if (this.mProcessCollection.ProcessItems.Exists((ProcessItem e) => e.FunctionSign.FullCode == callMethodInstruction.FunctionCode))
            {
                return this.Invoke(callMethodInstruction);
            }

            //如果在处理器集合没有对应的功能号,而服务端日志记录器集合 包含该功能号，
            if (this.mServicesLogger.ContainsKey(callMethodInstruction.FunctionCode) && this.mServicesLogger[callMethodInstruction.FunctionCode].Items.Count > 0)
            {
                //获取该功能号对应的日志记录器集合
                ServiceLogger serviceLogger = this.mServicesLogger[callMethodInstruction.FunctionCode];

                //依次重试日志记录器的所有集合 只要有一个成功则立即返回
                do
                {
                    //获取一条日志记录器
                    ServiceLoggerItem service = serviceLogger.GetService();
                    try
                    {
                        //使用执行器 调用Invoke方法
                        CarrierJson result = service.Performer.Invoke(callMethodInstruction);
                        service.LastCallTime = DateTime.Now;
                        return result;
                    }
                    catch (Exception innerException)
                    {
                        this.OnError(new InternalSystemException("An error occurred while executing a business request using a server object in the remote cache during internal calls.", this, innerException));
                        ServiceLogger obj = serviceLogger;
                        lock (obj)
                        {
                            serviceLogger.Items.Remove(service);
                        }
                    }
                }
                while (serviceLogger.Items.Count > 0);

                //递归调用（深度优先遍历）
                return this.LocalMethodCall(callMethodInstruction);
            }


            //获取连接信息
            List<ConnectedMappingInfo> connectedMappings = this.mRemoteControlCommandInterpreter.ConnectedMappings;
            //获取在线的服务器连接信息
            List<ConnectedMappingInfo> list;
            lock (connectedMappings)
            {
                list = new List<ConnectedMappingInfo>(this.mRemoteControlCommandInterpreter.ConnectedMappings.FindAll((ConnectedMappingInfo e) => !e.Disconnected));
            }
            if (list.Count == 0)
            {
                return new CarrierJson("Not found the local method and anyone server node supporting the function code '" + callMethodInstruction.FunctionCode + "'.");
            }
            list.Sort(delegate (ConnectedMappingInfo a, ConnectedMappingInfo b)
            {
                int num = a.FailedCount.CompareTo(b.FailedCount);
                if (num == 0)
                {
                    num = ((new Random().Next(1, int.MaxValue) % 2 == 0) ? -1 : 1);
                }
                return num;
            });
             
            //遍历所有的在线的服务器地址
            foreach (ConnectedMappingInfo connectedMappingInfo in list)
            {
                try
                {
                    //获取含有FunctionCode的最合适的服务器IP地址
                    ResultData<IP> serverIP = connectedMappingInfo.Performer.GetServerIP(callMethodInstruction.FunctionCode);
                    if (serverIP.Succeed)
                    {
                        try
                        {
                            //获取远程服务器上执行器
                            ResultData<ServiceRemoteMethodCallPerformer> remotingObject = NetManager.GetRemotingObject<ServiceRemoteMethodCallPerformer>((IP)connectedMappingInfo.IPAddress.ToString(), NetManager.JobServicePort);
                            if (remotingObject.Succeed)
                            {
                                ServiceLoggerItem serviceLoggerItem = new ServiceLoggerItem
                                {
                                    IP = connectedMappingInfo.IPAddress,
                                    LastCallTime = DateTime.Now,
                                    Performer = remotingObject.Data
                                };
                                lock (this.mServicesLogger)
                                {
                                    ServiceLogger serviceLogger2;
                                    if (this.mServicesLogger.ContainsKey(callMethodInstruction.FunctionCode))
                                    {
                                        serviceLogger2 = this.mServicesLogger[callMethodInstruction.FunctionCode];
                                    }
                                    else
                                    {
                                        serviceLogger2 = new  ServiceLogger();
                                        this.mServicesLogger.Add(callMethodInstruction.FunctionCode, serviceLogger2);
                                    }
                                    serviceLogger2.Items.Add(serviceLoggerItem);
                                }
                                try
                                {
                                    //在远程服务器上执行方法调用
                                    return serviceLoggerItem.Performer.Invoke(callMethodInstruction);
                                }
                                catch (Exception innerException2)
                                {
                                    this.OnError(new InternalSystemException("During an internal call, an error occurred while using a remote server to perform a business request.", this, innerException2));
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                catch
                {
                    ConnectedMappingInfo connectedMappingInfo2 = connectedMappingInfo;
                    int failedCount = connectedMappingInfo2.FailedCount;
                    connectedMappingInfo2.FailedCount = failedCount + 1;
                }
            }
            return new CarrierJson("Could not find any method to support function code '" + callMethodInstruction.FunctionCode + "' on the LAN server.");
        }


        /// <summary>
        /// 控制命令 functionCode 前缀
        /// </summary>
        private const string CONTROL_FUNCTION_CODE_FIX = "CTRL";


        /// <summary>
        /// 要加载的程序集集合
        /// </summary>
        private readonly List<Assembly> _AssemblyList = new List<Assembly>();


        /// <summary>
        /// 服务端发送在线广播
        /// </summary>
        private SendServiceOnlineBroadcast mBroadcast = new SendServiceOnlineBroadcast();


        /// <summary>
        /// 远程控制器命令拦截器
        /// </summary>
        private readonly RemoteControlCommandInterpreter mRemoteControlCommandInterpreter = new RemoteControlCommandInterpreter();


        /// <summary>
        /// 处理器集合
        /// </summary>
        private readonly ProcessCollection mProcessCollection = new ProcessCollection();


        /// <summary>
        /// 服务记录器
        /// </summary>
        private readonly Dictionary<string, ServiceLogger> mServicesLogger = new Dictionary<string, ServiceLogger>();



    }
}
